﻿/**
   данный компонент сиволизирует аквалангиста. Этот компонент будет собирать звезды, подниматься по канату, опрашивать компрессор, сообщать по радио, какую звезду он нашел, какую увидел
 */

(F.AqualungerStateEnum = function () {
    var ase = F.AqualungerStateEnum;
    ase.Ready = "Ready";
    ase.Down = "Down";
    ase.PersecutionStar = "PersecutionStar";
    ase.LowOxygen = "LowOxygen";
    ase.Up = "Up";
    ase.BringStarToBase = "BringStarToBase";
    ase.FillingOxygen = "FillingOxygen";
    ase.GoOut = "GoOut";
})();

(F.AqualungerMoveStateEnum = function () {
    var ame = F.AqualungerMoveStateEnum;
    ame.Left = "Left";
    ame.Right = "Right";
    ame.Up = "Up";
    ame.Down = "Down";
    ame.None = "None";

})();

(function () {
    "use strict";

    F.Aqualunger = function (container, environment, radio, x, y) {
        var self = this;
        F.Aqualunger.superclass.constructor.apply(self, [container, environment]);
        
        self.environment.registerAqualunger(this);
        

        self.radio = radio;
        self.velocity = 20; //Скорость аквалангиста 20 пикселей в секунду
        self.minAmountOxygen = 5000; //Минимальный объем кислорода, при котором водолаз идет на судно для попосления балона
        self.oxygenConsuption = 50; //Расход кислорода 50мл в секунду
        self.oxygenStarConsuption = 1; //Расход кислорода на оценку звезды в сукунду
        self.oxygenStarConsuptionForUp = 50; //Расход кислорода на оценку, для компенсации балласта
        self.oxygenCounterbalance = 50;

        self.pickRadius = 25; //Радиус, внутри которого, аквалангист сможет поднять звезду

        self.oxygenTank = new F.OxygenTank(container, environment); //Бак с кислородом

        self.x = x;
        self.y = y;

        self.firstStar = null;
        self.secondStar = null;


        //Картинки аквалангиста
        self.leftAqualunger = null;
        self.rightAqualunger = null;
        self.upDownAqualunger = null;
        self.thought = null;

        self.isThoughtShowing = false;

        self.moveState = F.AqualungerMoveStateEnum.None;

        self.state = F.AqualungerStateEnum.Ready;

        self.aquaCenter = null;
        self.firstStarCenter = null;
        self.secondStarCenter = null;
        self.thoughtCenter = null;

        self._initializeResourses();
        self._initializeCenterCoor();

        /**
            аквалангмчт инициализируется тремя картинками. движения, влево вправо вверх.
            Во всех случаях может отобразиться всплывающая подсказка, и он может нести одновременно две звезды.
            Для этого определены заранее прописанные центры, в которые будут помещены звезды, и подсказка
        */
                
        //====Переменые модулей
        self.searchSideSign = Math.random() > 0.5? -1: 1; //Задает направление перемещения аквалангиста при поиске звезд //Двигаемся влево

        self.isRefuelOxygenStart = false; //Начал ли текущий водолаз наполнять балон кислородом
        self.isOxygenTankAlreadyRemoved = false;

        //Всплытие
        //Остановки при всплытии
        self.firstUpStopTime = 5; //5 секунд остановка
        self.secondUpStopTime = 10;
        self.thirdUpStopTime = 15;
        self.currentUpStopTime = 0; //Сколько уже стоим на текущей остановке
        self.isUseOxygenToCounterbalance = false;
            
        self.firstUpStop = false;
        self.secondUpStop = false;
        self.thirdUpStop = false;
        
        self.isExit = false; //Уходим с поля
        self.isGoOutStart = false;

        //Преследуемая звезда
        self.setCurrentPersecutionStar(null);

        self.process(0);
    };

    extend(F.Aqualunger, F.Shape);

    var ap = F.Aqualunger.prototype;

    ap._initializeResourses= function () {
        var self = this;
        
        //влево
        var img = self.leftAqualunger = new Image();
        img.src = "images/diver-go-harvest.png";
        img.className = "aqualunger";
        self._hide(img);
        self.container.appendChild(img);

        //Вправо
        img = self.rightAqualunger = new Image();
        img.src = "images/diver-go-home.png";
        img.className = "aqualunger";
        self._hide(img);
        self.container.appendChild(img);

        //Ввех/Вниз
        img = self.upDownAqualunger = new Image();
        img.src = "images/diver-tros.png";
        img.className = "aqualunger";
        self._hide(img);
        self.container.appendChild(img);

        //Надо отдохнуть
        img = self.thought = new Image();;
        img.src = "images/thought.png";
        img.className = "aqualunger-thought";
        if (!self.isThoughtShowing){
            self._hide(img);
        }
        self.container.appendChild(img);


    };

    ap._initializeCenterCoor = function() {
        var self = this;

        var ame = F.AqualungerMoveStateEnum;
        self.aquaCenter = {};
        self.aquaCenter[ame.Left] = { x : 27, y: 34 };
        self.aquaCenter[ame.Right] = { x: 37, y: 34 };
        self.aquaCenter[ame.Up] = { x: 25, y: 34 };
        self.aquaCenter[ame.Down] = { x: 25, y: 34 };
        
        //Координаты звезды, относительно левого края
        self.firstStarCenter = {}; 
        self.firstStarCenter[ame.Left] = { x : -40, y: 0 };
        self.firstStarCenter[ame.Right] = { x: 40, y: 0 };
        self.firstStarCenter[ame.Up] = { x: 25, y: 30  };
        self.firstStarCenter[ame.Down] = { x: 25, y: 30 };

        //Координаты звезды, относительно левого края
        self.secondStarCenter = {}; 
        self.secondStarCenter[ame.Left] = { x : -20, y: -15 };
        self.secondStarCenter[ame.Right] = { x: 20, y: -15 };
        self.secondStarCenter[ame.Up] = { x: 30, y: 0 };
        self.secondStarCenter[ame.Down] = { x: 30, y: 0 };

        self.thoughtCenter = {}; 
        self.thoughtCenter[ame.Left] = { x : -125, y: 80 };
        self.thoughtCenter[ame.Right] = { x: -115, y: 80 };
        self.thoughtCenter[ame.Up] = { x: -135, y: 80 };
        self.thoughtCenter[ame.Down] = { x: -135, y: 80 };
    }

    ap.process = function (dt) {
        var self = this;
        self.breath(dt);
        var isOxygenLevelLow = self.isOxygenLevelLow();


        if (isOxygenLevelLow && !self.isExit && self.state !== F.AqualungerStateEnum.BringStarToBase){ //Если возвращаемся со звездами, забиваем на кислород
            self.setCurrentPersecutionStar(null);
            self.dropAllStar();
            self.state = F.AqualungerStateEnum.LowOxygen;
        }

        if (!self.isGoOutStart && self.isExit && self.state !== F.AqualungerStateEnum.BringStarToBase){
            self.setCurrentPersecutionStar(null);
            self.dropAllStar();
            self.state = F.AqualungerStateEnum.GoOut;
            self.isGoOutStart = true;
        }

        var isDriverOnBase = self.environment.isDriverOnBase(self);
        //Здесь происходит обработка стейтов
        switch(self.state) {
            case F.AqualungerStateEnum.LowOxygen:
                if (!self.isThoughtShowing)
                    self.showThought();
                if (!isDriverOnBase){
                    self.swimToBoat(dt);
                } else {
                    self.refuelOxygenTank(dt);
                    if (self.oxygenTank.isFull() && self.isOxygenTankAlreadyRemoved === false){
                        //Заправка завершена.
                        self.hideThought();
                        self.state = F.AqualungerStateEnum.Ready;
                    }
                }
                break;
            case F.AqualungerStateEnum.PersecutionStar:
                self.persecutionStar(dt);
                break;
            case F.AqualungerStateEnum.BringStarToBase:
                if (!isDriverOnBase){
                    self.swimToBoat(dt);
                } else {
                    //Скидываем звезду. Возвращаемся в состояние Ready
                    self.dropStarToBoat();
                    self.state = F.AqualungerStateEnum.Ready;
                }
                break;
            case F.AqualungerStateEnum.Down:
                self.swimToBottom(dt);
                if (self.environment.isDriverOnBottom(this)){
                    self.state = F.AqualungerStateEnum.PersecutionStar;    
                }
                break;
            case F.AqualungerStateEnum.Ready:
                self.state = F.AqualungerStateEnum.Down;
                //Сбрасываем все переменные
                self.isUseOxygenToCounterbalance = false;
                self.isRefuelOxygenStart = false;
                self.isOxygenTankAlreadyRemoved = false;
                self.currentUpStopTime = 0; //Сколько уже стоим на текущей остановке
                self.firstUpStop = false;
                self.secondUpStop = false;
                self.thirdUpStop = false;
                break;
            case F.AqualungerStateEnum.GoOut:
                if (!isDriverOnBase){
                    self.swimToBoat(dt);
                } else {
                    self.destroy();
                }
                break;
            default:
                throw "Logical error. State aqualunger is not available.";
        }    
    };

    //Определяет, не опустился ли уровень кислорода ниже нормы в балоне
    ap.isOxygenLevelLow = function(){
        var self = this;
        return self.oxygenTank.getCurrentCapacity() < self.minAmountOxygen;
    }

    ap.dropStarToBoat = function(){
        var self = this;
        if (self.firstStar){
            self.radio.setStarAsCollected(self.firstStar, self);
            self.firstStar.destroy();
            self.firstStar = null;
        }
        if (self.secondStar){
            self.radio.setStarAsCollected(self.secondStar, self);
            self.secondStar.destroy();
            self.secondStar = null;
        }
    }

    //===== Модули поведения аквалангиста ===========

    ap.pickStar = function(star){
        var self = this;
        if (!self.firstStar){
            self.pickFirstStar(star);
            return;
        } else if (!self.secondStar){
            self.pickSecondStar(star);
            return;
        }
    }

    ap.pickFirstStar = function(star){
        //Проверяем условие. Если близко и в той руке ничего нет, то
        var self = this;
        if (self.firstStar != null)
            throw "Logical error. The first slot is occupied.";
        if (!(star.getX() > self.x - self.pickRadius && star.getX() < self.x + self.pickRadius))
            throw "Logical error. The star is beyond the capabilities of setting.";
        self.firstStar = star;
        star.captureStar(this);
    }

    ap.pickSecondStar = function(star){
        var self = this;
        if (self.secondStar != null)
            throw "Logical error. The first slot is occupied.";
        if (!(star.getX() > self.x - self.pickRadius && star.getX() < self.x + self.pickRadius))
            throw "Logical error. The star is beyond the capabilities of setting.";
        self.secondStar = star;   
        star.captureStar(this);
    }

    //Дыхание
    ap.breath = function(dt){
        var self = this;
        if (self.environment.isDriverOnBase(self)){
            return;
        }
        //Дышим.
        self.oxygenTank.getOxygen(self.oxygenConsuption * dt);
        //Увеличенная нагрузка из-за звезд
        if (self.firstStar)
            self.oxygenTank.getOxygen(self.oxygenStarConsuption * self.firstStar.getRate() * dt);
        if (self.secondStar)
            self.oxygenTank.getOxygen(self.oxygenStarConsuption * self.secondStar.getRate() * dt);
    }

    ap.dropAllStar = function(){
        //Скидываем звезды, которые находятся в руках
        var self = this;
        self.dropStar(self.firstStar);
        self.dropStar(self.secondStar);
    }

    //Скинуть звезду
    ap.dropStar = function(star){
        //Скидываем звезды, которые находятся в руках
        if (!star)
            return;
        var self = this;

        self._validateFirstStarPosition();
        self._validateSecondStarPosition();

        if (self.firstStar === star){
            self.firstStar = null;
        }

        if (self.secondStar === star){
            self.secondStar = null;
        }
        star.freeStar(this);
        if (self.radio.isStarBusy(star, self)){
            self.radio.setStarAsFree(star, self);
        }
    }

    //Заправка кислородом
    ap.refuelOxygenTank = function(dt){
        //Если находимся в оласти лодки. Проверяем, свободен ли компрессор.
        //Если да. то занимаем его.
        //Перемещаемся к нему влево.
        //Заполняем бак
        //Проверяем, заполнен ли бак
        //Отходим от компрессора
        //Вынимаем балон с кислородом
        var self = this;
        var boatArea = self.environment.getAreaBoat();
        
        var insideBoat = self.environment.isDriverOnBase(self);
        if (!insideBoat)
            throw "Logical error. The diver can not access to the compressor, if it is not on the boat.";
        var compressor = self.environment.getCompressor(self);
        if (!self.isRefuelOxygenStart){
            //Если не начали наполнять, то проверяем, свободен ли компрессор
            if (compressor.isBusy())
                return; //Занят. Ждем.
            //Свободен.
            //Кидаем в него балон. И начинаем наполнять
            compressor.setOxygenTank(self.oxygenTank);
            self.isRefuelOxygenStart = true;
        }

        var oxygenTankIsFull = self.oxygenTank.isFull();

        //Окончание наполнения определяем по переменной isRefuelOxygenStart
        //Проверяем. Стоим ли мы возле компрессора?
        
        if (!oxygenTankIsFull && boatArea.x + 5 < self.x){
            self.moveLeft(dt);
        }
        
        //Отлично. Встали возле компрессора.
        //Проверяем, наполнился ли балон
        if (oxygenTankIsFull && ! self.isOxygenTankAlreadyRemoved){
            compressor.removeOxygenTank();
            self.isOxygenTankAlreadyRemoved = true;
        }

        //Проверяем, если балон наполнился, и мы его удалили, то начинаем движение к области погружения
        if (oxygenTankIsFull && self.isOxygenTankAlreadyRemoved){
            //Проверяем. Достигли ли мы области погружения
            var verticalArea = self.environment.getAreaForLifting();
            if (self.x < verticalArea.x){
                self.moveRight(dt);
            }
            else {
                //Достигли области погружения
                //Сбрасываем переменные
                self.isRefuelOxygenStart = false;
                self.isOxygenTankAlreadyRemoved = false; 
            }
        }
    }

    ap.persecutionStar = function(dt){
        var self = this;
        var stars = self.environment.getVisibleStars(self);

        //Основная логика работы
        //Нет звезд, штатный режим. Патрулируем
        //В руках звезда, и не видим звезд вокруг, несем на базу.
        //Видим, чем можно поживиться. Преследуем.
        //В руках звезды. Видим круче, выкидываем свое, берем круче


        //Есть свободные звезды в зоне видимости
        var freeStars = [];
        for (var i = 0, length = stars.length; i < length; i++){
            var star = stars[i];
            if (!self.radio.isStarBusy(star, self)){
                freeStars.push(star);
            }
        }

        var status = self._getPersecutionStarStatus(freeStars);

        if (!status.isChanged && self.currentPersecutionStar){
            self._followStar(dt, status);
            return;   
        }

        if (freeStars.length > 0){
            
            if (status.needPersecution){
                self._followStar(dt, status);
            } else {
                self._moveToBaseWithStars(dt);
            }
        } else {//Нет звезд, штатный режим. Патрулируем или несем если есть на базу
            if (self.firstStar || self.secondStar){
                self._moveToBaseWithStars(dt);
            } else {
                self._searchStars(dt);
            }
            return;
        }
    }

    ap._getPersecutionStarStatus = function(freeStars){
        var self = this;

        var needPersecution = false; //Нужно ли преследовать звезду
        ////var freeStars = freeStars;
        var isChanged = true;
        var maxStar = null;
        var removeFirstStar = false;
        var removeSecondStar = false;
        var currentPersecutionStar = null;

        //Если звезд нет
        if (freeStars.length === 0 && self.currentPersecutionStar){
            needPersecution = true;
            isChanged = false;
            //Без изменений, преследуем
        } else {
            if (self.firstStar && self.secondStar && freeStars.length !== 0) {//Руки заняты
                maxStar = self._getMaxStar(freeStars);
                //Проверяем, на руках круче?
                if (maxStar.getRate() > self.firstStar.getRate()){
                    //Проверяем, а вторая звезда больше первой
                    if (self.firstStar.getRate() > self.secondStar.getRate()){
                        //Больше, значит выкидываем вторую 
                        removeSecondStar = true;
                        currentPersecutionStar = maxStar;
                        needPersecution = true;
                    } else {
                        removeFirstStar = true;
                        currentPersecutionStar = maxStar;
                        needPersecution = true;
                    }
                } else if (maxStar.getRate() > self.secondStar.getRate()){
                    if (self.secondStar.getRate() > self.firstStar.getRate()){
                        removeFirstStar = true;
                        currentPersecutionStar = maxStar;
                        needPersecution = true;
                    } else {
                        removeSecondStar = true;
                        currentPersecutionStar = maxStar;
                        needPersecution = true;
                    }
                }
            } else if (freeStars.length > 0 && ((!self.firstStar && !self.secondStar) || (self.firstStar || self.secondStar))){//В руках ничего нет или что- то есть
//                if (self.currentPersecutionStar)
//                    freeStars.push(self.currentPersecutionStar);
                maxStar = self._getMaxStar(freeStars);
            
                needPersecution = true;

                if (!self.currentPersecutionStar || self.currentPersecutionStar.getRate() < maxStar.getRate()){
                    currentPersecutionStar = maxStar;
                } else {
                    isChanged = false;
                }
            }
        }

        return {
            isChanged: isChanged,
            needPersecution: needPersecution,
            removeFirstStar: removeFirstStar, 
            removeSecondStar: removeSecondStar,
            currentPersecutionStar: currentPersecutionStar
        };
    }

    ap._moveToBaseWithStars = function(dt){
        var self = this;
        //Движемся в сторону подъема
        self._moveToLift(dt);
        //Достигли подъема ?
        if (self.environment.isDriverOnLiftingArea(self)){
            //Переключаемся в режим поднятия и сброса оценок
            self.state = F.AqualungerStateEnum.BringStarToBase;
            return;
        }    
    }

    /**
       В данной функции просто двигаемся к выбранной звезде.
     */
    ap._followStar = function(dt, status){
        var self = this;

        if (status.removeFirstStar){
            self.radio.setStarAsFree(self.firstStar, self);   
            self.dropStar(self.firstStar); 
        }

        if (status.removeSecondStar){
            self.radio.setStarAsFree(self.secondStar, self);    
            self.dropStar(self.secondStar); 
        }

        if (status.isChanged && self.currentPersecutionStar !== status.currentPersecutionStar) {
            self.setCurrentPersecutionStar(status.currentPersecutionStar);
        }

        var star = self.currentPersecutionStar;

        if (!star)
            return;

        //Если находимся на расстоянии возможности поднять звезду, стоим
        
        if (self.x - self.pickRadius < star.getX() && self.x + self.pickRadius > star.getX()) {
            //Если звезда еще не упала, то ее нельзя захватывать
            if (star.isNotMobile()) {
                self.pickStar(self.currentPersecutionStar);
                self.currentPersecutionStar = null;
            }
        } else {
            if (self.x > star.getX()){
                self.moveLeft(dt);
            } else {
                self.moveRight(dt);
            }
        }

    }

    ap.setCurrentPersecutionStar = function(newCurrentPersecutionStar){
        var self = this;
        if (self.currentPersecutionStar && self.currentPersecutionStar === newCurrentPersecutionStar)
            throw "Logic error. Попытка повторной установки одного и того же значения";

        //Оповещаем об освобождении
        if (self.currentPersecutionStar){
            self.radio.setStarAsFree(self.currentPersecutionStar, self);
        }
        if (newCurrentPersecutionStar){
            self.radio.setStarAsBusy(newCurrentPersecutionStar, self);
        }
        self.currentPersecutionStar = newCurrentPersecutionStar
    }

    ap._getMaxStar = function(stars){
        if (stars.length === 0){
            return null;
        }
        var maxStar = stars[0];
        for (var i = 1, length = stars.length; i < length; i++){
            if (stars[i].getRate() > maxStar.getRate()){
                maxStar = stars[i];
            }
        }
        return maxStar;
    }

    /**
       Просто ходит туда сюда и ищет звезды
     */
    ap._searchStars = function(dt){
        var self = this;
        var area = self.environment.getBorderOfBottom();

        //Проверяем границы Если находимя за пределами области поиск. То это ошибка
        if (area.y > self.y || area.y + area.height < self.y)
            throw "Logical error. Search has started outside of the bottom."

        //Проверяем правую и левую границую
        if (area.x > self.x){
            self.searchSideSign = 1;    //Двигаемся вправо   
        }
        if (area.x + area.width < self.x){
            self.searchSideSign = -1;   //Двигаемся влево
        }

        //Сдвигаемся
        if (self.searchSideSign > 0){
            self.moveRight(dt);
        } else {
            self.moveLeft(dt);
        }
    }

    ap._moveToLift = function(dt){
        var self = this;
        var verticalArea = self.environment.getAreaForLifting();    

        //Находимся слева от подъема?
        //Доехали до середины подъема?

        if (self.x < verticalArea.x + verticalArea.width / 2){
            self.moveRight(dt);
        } else {
            self.moveLeft(dt);
        }
    }

    ap.swimToBoat = function(dt){
         var self = this;
         var bottomArea = self.environment.getBorderOfBottom();
         var verticalArea = self.environment.getAreaForLifting();

         var isBottomArea = self.environment.isDriverOnBottom(self);
         var isSwimArea = self.environment.isDriverOnLiftingArea(self);
         //Проверки
         //Если не находимся в области подъема,
        if (!isBottomArea && !isSwimArea)
            throw "Logical error. The rise has started outside the area of the bottom and lifting.";

        //1) Мы находимся в области подъема?
        if (isSwimArea){    
            //Компенсировали балласт?
            if (!self.isUseOxygenToCounterbalance){
                //Нужно затратить кислород для подъема
                var oxygenForUp = self.oxygenCounterbalance;
                //Поднимаемся с оценкой?
                if (self.firstStar){
                    oxygenForUp += self.firstStar.getRate() * self.oxygenStarConsuptionForUp;
                }
                if (self.secondStar) {
                    oxygenForUp += self.secondStar.getRate() * self.oxygenStarConsuptionForUp;
                }
                self.oxygenTank.getOxygen(oxygenForUp);
                self.isUseOxygenToCounterbalance = true;
            }

            if (!self.firstUpStop && self.environment.isPassedThirdScreen(this)){
                if (self.currentUpStopTime < self.firstUpStopTime){
                    self.currentUpStopTime += dt; //Ждем на первой остановке
                    return;
                } else {
                    self.currentUpStopTime = 0;
                    self.firstUpStop = true
                }
            } else if (!self.secondUpStop && self.environment.isPassedSecondThirdScreen(this)){
                if (self.currentUpStopTime < self.secondUpStopTime){
                    self.currentUpStopTime += dt; //Ждем на второй остановке
                    return; 
                } else {
                    self.currentUpStopTime = 0;
                    self.secondUpStop = true;
                }
            } else if (!self.thirdUpStop && self.environment.isPassedFourFifthsScreen(this)){
                if (self.currentUpStopTime < self.thirdUpStopTime){
                    self.currentUpStopTime += dt; //Ждем на третьей остановке
                    return;
                } else {
                    self.currentUpStopTime = 0;
                    self.thirdUpStop = true;
                }
            }

            //Если еще не достигли верхей границы, плывем наверх
            if (!(self.y >= verticalArea.y + verticalArea.height - 5)){
                self.moveUp(dt);
            }

        } else if (isBottomArea){
            self._moveToLift(dt);
        }
    }

    ap.swimToBottom = function(dt){
        var self = this;
         var bottomArea = self.environment.getBorderOfBottom();
         var verticalArea = self.environment.getAreaForLifting();

         var isBottomArea = self.environment.isDriverOnBottom(self);
         var isSwimArea = self.environment.isDriverOnLiftingArea(self);
         //Проверки
         //Если не находимся в области подъема,
        if (!isBottomArea && !isSwimArea)
            throw "Logical error. The rise has started outside of the bottom and of the descent.";

        //1) Мы находимся в области спуска?
        if (isSwimArea){
            //Если еще не достигли нижней границы, плывем вниз
            if (!(self.y <= verticalArea.y + 5)){
                self.moveDown(dt);
            }
        }
    }

    //===== /Модули поведения аквалангиста ===========



    //===== Механическое перемещение ===========

    ap.showThought = function () {
        var self = this;
        self.isThoughtShowing = true;
        self._validateThoughtPosition();
        self._show(self.thought);
    }

    ap.hideThought = function () {
        var self = this;
        self.isThoughtShowing = false;
        self._hide(self.thought);
    }

    ap.moveLeft = function (dt) {
        var self = this;
        if (self.moveState !== F.AqualungerMoveStateEnum.Left){
            self.moveState =  F.AqualungerMoveStateEnum.Left;
            self._show(self.leftAqualunger);
            self._hide(self.rightAqualunger);
            self._hide(self.upDownAqualunger);
        }

        self.x -= self.velocity * dt;
        //self.y = self.y;

        self._updatePositionAqualunger(self.leftAqualunger);
    }

    ap.moveRight = function (dt) {
        var self = this;
        if (self.moveState !== F.AqualungerMoveStateEnum.Right){
            self.moveState =  F.AqualungerMoveStateEnum.Right;
            self._hide(self.leftAqualunger);
            self._show(self.rightAqualunger);
            self._hide(self.upDownAqualunger);
        }

        self.x += self.velocity * dt;
        //self.y = self.y;

        self._updatePositionAqualunger(self.rightAqualunger);
    }

    ap.moveUp = function (dt) {
        var self = this;
        if (self.moveState !== F.AqualungerMoveStateEnum.Up){
            self.moveState =  F.AqualungerMoveStateEnum.Up;
            self._hide(self.leftAqualunger);
            self._hide(self.rightAqualunger);
            self._show(self.upDownAqualunger);
        }

        //self.x = self.x;
        self.y += self.velocity * dt;

        self._updatePositionAqualunger(self.upDownAqualunger);        
    }

    ap.moveDown = function (dt) {
        var self = this;
        if (self.moveState !== F.AqualungerMoveStateEnum.Down){
            self.moveState =  F.AqualungerMoveStateEnum.Down;
            self._hide(self.leftAqualunger);
            self._hide(self.rightAqualunger);
            self._show(self.upDownAqualunger);
        }

        //self.x = self.x;
        self.y -= self.velocity * dt;

        self._updatePositionAqualunger(self.upDownAqualunger);        
    }

    ap._updatePositionAqualunger = function(aqualungerImg){
        var self = this;
        var xy = self.environment.translateGameToReal(self.x - self.aquaCenter[self.moveState].x, self.y + self.aquaCenter[self.moveState].y);
        aqualungerImg.style.left = xy.x + "px";
        aqualungerImg.style.top = xy.y + "px";   

        //Если есть звезды, то устанавливаем для них позиции
        self._validateFirstStarPosition();
        self._validateSecondStarPosition();
        self._validateThoughtPosition();

    }

    ap._validateThoughtPosition = function(){
        var self = this;
        if (self.isThoughtShowing){
            var thoughtXY = self.environment.translateGameToReal(self.x + self.thoughtCenter[self.moveState].x, self.y + self.thoughtCenter[self.moveState].y);
            self.thought.style.left = thoughtXY.x + "px";
            self.thought.style.top = thoughtXY.y + "px";
        }
    }


    ap._validateFirstStarPosition = function(){
        var self = this;
        if (self.firstStar){
            //Координаты звезд
            self.firstStar.setCoord(
                self.x + self.firstStarCenter[self.moveState].x, 
                self.y + self.firstStarCenter[self.moveState].y
            );
        }
    }

    ap._validateSecondStarPosition = function(){
        var self = this;
        if (self.secondStar){
            self.secondStar.setCoord(
                self.x + self.secondStarCenter[self.moveState].x, 
                self.y + self.secondStarCenter[self.moveState].y
            );
        }
    }

    //===== /Механическое перемещение ===========

    ap.goOut = function(){
        var self = this;
        self.isExit = true;
    }

    ap.isGoOut = function(){
        var self = this;
        return self.isExit || self.state === F.AqualungerStateEnum.GoOut;
    }


    ap._hide = function (dom) {
        dom.style.display = "none";
    }

    ap._show = function (dom) {
        dom.style.display = "block";
    }

    ap.destroy = function () {
        var self = this;
        F.Aqualunger.superclass.destroy.apply(self);
        self.environment.unregisterAqualunger(self);
        self.container.removeChild(self.leftAqualunger);
        self.container.removeChild(self.rightAqualunger);
        self.container.removeChild(self.upDownAqualunger);
        self.container.removeChild(self.thought);
        self.leftAqualunger = null;
        self.rightAqualunger = null;
        self.upDownAqualunger = null;
        self.thought = null;
    };

    ap = null;
} ());